# -*- coding: utf-8 -*-

import requests
import json

from enum import Enum
from typing import List
from conf.entity.module.git_config import OpsConfig, GitProject, GitBranchPair


class OpsProductType(Enum):
    NG = 1
    DING_TALK = 2


class OpsProject:
    """
    ldap项目, 例如callout-service
    """
    id: str
    name: str
    code: str
    modules: List[str]

    def __init__(self):
        self.modules = []


class OpsProduct:
    """
    ldap项目信息
    """
    type: OpsProductType
    id: int
    name: str
    request_id: int
    request_version_name: str
    cluster_name: str
    cluster_env: str

    def __init__(self, product_type: OpsProductType):
        self.type = product_type


class OpsOperation:
    ops_config: OpsConfig

    def __init__(self, ops_config: OpsConfig):
        self.ops_config = ops_config
        self._login()

    @staticmethod
    def _get_base_post_headers() -> json:
        return {
            "content-type": "application/json;charset=UTF-8"
        }

    def _get_authorized_post_headers(self):
        headers = self._get_base_post_headers()
        headers['authorization'] = 'BEARER ' + self.ops_config.access_token
        return headers

    def _get_authorized_get_headers(self):
        return {
            'authorization': 'BEARER ' + self.ops_config.access_token
        }

    def _login(self):
        if self.ops_config is None or self.ops_config.access_token != "":
            return
        token_url = 'https://ops.maycur.com/api/token/'

        payload = {
            'username': self.ops_config.ldap_config.user_account,
            'password': self.ops_config.ldap_config.user_password
        }
        payload_json = json.dumps(payload)

        res = requests.post(token_url, data=payload_json, headers=self._get_base_post_headers())
        if res.status_code == 200:
            res_json = json.loads(res.content)
            self.ops_config.access_token = res_json['access']
            print(f'get ops access token for user: {self.ops_config.ldap_config.user_account}')
        else:
            print(f'failed to get ops token, reason: {res.reason}')

    def _get_project_info(self, ops_code: str) -> OpsProject:
        project_info_url = f'https://ops.maycur.com/api/project/{ops_code}/'

        res = requests.get(project_info_url, headers=self._get_authorized_get_headers())

        if res.status_code == 200:
            project_json = json.loads(res.content)
            ops_project = OpsProject()
            ops_project.id = project_json['id']
            ops_project.name = project_json['name']
            ops_project.code = project_json['code']
            ops_project.modules = project_json['modules']
            return ops_project
        else:
            print(f'failed to get project info: {ops_code}, reason: {res.reason}')

    def _get_product_info(self, ops_code: str):
        product_info_url = f'https://ops.maycur.com/api/project/{ops_code}/product/'

        res = requests.get(product_info_url, headers=self._get_authorized_get_headers())

        ops_product_dict = {}

        if res.status_code == 200:
            product_list = json.loads(res.content)
            for product_item in product_list:
                product_name = product_item['name']
                if '报销旗舰版' == product_name:
                    ops_product = OpsProduct(OpsProductType.NG)
                    ops_product_dict[OpsProductType.NG] = ops_product
                elif '报销钉钉版' == product_name:
                    ops_product = OpsProduct(OpsProductType.DING_TALK)
                    ops_product_dict[OpsProductType.DING_TALK] = ops_product
                else:
                    print(f'product_list: {product_list}')
                    continue
                ops_product.id = product_item['id']
                ops_product.name = product_name
                deployment_requests = product_item['deployment_requests']
                if len(deployment_requests) > 0:
                    deployment_item = deployment_requests[0]
                    ops_product.request_id = deployment_item['id']
                    ops_product.request_version_name = deployment_item['product_version_name']
                    ops_product.cluster_name = deployment_item['cluster_name']
                    ops_product.cluster_env = deployment_item['cluster_environment']
        else:
            print(f'failed to get product info: {ops_code}, reason: {res.reason}')
        return ops_product_dict

    def create_deployment_request_if_need(self, branch_pair: GitBranchPair, git_project: GitProject):
        bulk_create_url = 'https://ops.maycur.com/api/deployment/request/bulk_create/'
        submit_url = 'https://ops.maycur.com/api/deployment/request/submit/'

        if self.ops_config is None or not self.ops_config.do_make_request:
            return
        if git_project.branches_no_diff:
            print(f'branch no diff, no need to make ldap request, project: {git_project.name}')
            return
        ops_code = git_project.ops_code
        ops_branch = branch_pair.ops_branch
        if ops_code == "":
            print(f'ldap code is empty for project: {git_project.name}')
            return
        if ops_branch == "":
            print(f'ldap branch is not set for project: {git_project.name}')
            return

        # get ldap project info
        ops_project = self._get_project_info(ops_code)
        if ops_project is None:
            print(f'ldap code {ops_code} not exist')
            return

        # get ldap product info
        ops_product_dict = self._get_product_info(ops_code)
        product_ng = ops_product_dict[OpsProductType.NG]
        product_ding_talk = ops_product_dict[OpsProductType.DING_TALK]
        product_request_ids = []

        # 提交旗舰版部署申请
        if self.ops_config.ops_ng and not git_project.ops_only_ding_talk:
            if hasattr(product_ng, 'request_id'):
                product_request_ids.append(product_ng.request_id)
        # 提交钉版部署申请
        if self.ops_config.ops_dingtalk and not git_project.ops_only_ng:
            if hasattr(product_ding_talk, 'request_id'):
                product_request_ids.append(product_ding_talk.request_id)

        if len(product_request_ids) == 0:
            print('request id not found now ...')
            return

        post_headers = self._get_authorized_post_headers()

        # ops部署申请备注
        ops_comment = self.ops_config.request_description
        if ops_comment is None or ops_comment == '':
            ops_comment = 'created by Maycur Pytools'

        # clusters, preceding_request_ids, manual_tasks is necessary, in case of server internal error
        bulk_create_payload = {
            'biz_type': 'PROJECT_DEPLOYMENT',
            'deploy_type': 'RELEASE',
            'project': ops_project.id,
            'branch': ops_branch,
            'modules': ops_project.modules,
            'product_request_ids': product_request_ids,
            'clusters': [],
            'preceding_request_ids': [],
            'manual_tasks': [],
            'comments': ops_comment
        }

        bulk_resp = requests.post(bulk_create_url, data=json.dumps(bulk_create_payload), headers=post_headers)
        if bulk_resp.status_code == 200:
            submit_payload = json.loads(bulk_resp.content)

            submit_resp = requests.post(submit_url, data=json.dumps(submit_payload), headers=post_headers)
            if submit_resp.status_code == 200:
                git_project.ops_created = True
                print(f'make ldap request successfully for project: {git_project.name}')
            else:
                print(f'fail to submit ldap request, reason: {submit_resp.reason}')
        else:
            print('request body:')
            print(json.dumps(bulk_create_payload))
            print(f'fail to bulk create ldap request, reason: {bulk_resp.reason}')
